package com.aurora.gulimall.search.thread;

import org.springframework.http.converter.json.GsonBuilderUtils;

import java.util.concurrent.*;

public class ThreadTest {
    public static ExecutorService executor = Executors.newFixedThreadPool(10);

    /**
     * 创建启动CompletableFuture异步编排
     * @param args
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start....");
//        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
//            System.out.println("当前线程： " + Thread.currentThread().getId());
//            int i = 10 / 2;
//            System.out.println("运行结果：" + i);
//        }, executor);
/**
 * 方法完成后的感知
 * */
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程： " + Thread.currentThread().getId());
//            int i = 10 / 0;
//            System.out.println("运行结果：" + i);
//            return i;
//        }, executor).whenComplete((res,exception)->{
//            //虽然能得到异常信息，但是没法修改返回数据
//            System.out.println("运行结果是:"+res+";异常："+exception);
////运行结果是:null;异常：java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
//        }).exceptionally(throwable -> {
//            //可以感知异常同时返回默认值
//            return -1;
//        });
/**
 * 方法完成后的处理
 * */
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程： " + Thread.currentThread().getId());
//            int i = 10 / 0;
//            System.out.println("运行结果：" + i);
//            return i;
//        }, executor).handle((res,exception)->{
//            if(res != null){
//                return res;
//            }
//            if(exception != null){
//                return -1;
//            }
//            return 0;
//        });// R apply(T t, U u);
//        System.out.println("CompletableFuture.supplyAsync:"+future.get());
//        //CompletableFuture.supplyAsync:-1
//        System.out.println("main...end....");
//    }
/**
 * 线程串行化
 * 1、thenRunxxx不能获取上一步执行结果
 * .thenRunAsync(() -> {
 *             System.out.println("任务2启动");
 *         }, executor);
 *
 * 2、thenAcceptxxx能接收上一步执行结果，无返回值
 * .thenAcceptAsync(res->{
 *             System.out.println("任务1执行结果："+res);
 *         });
 *
 * 3、thenApplyxxx能接收上一步执行结果，有返回值
 *.thenApplyAsync(res -> {
 *             System.out.println("上一步运行结果：" + res);
 *             return res * 2;
 *         });
 *
 *
 * */
//        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
//            System.out.println("当前线程： " + Thread.currentThread().getId());
//            int i = 10 / 4;
//            System.out.println("运行结果：" + i);
//            return i;
//        }, executor).thenApplyAsync(res -> {
//            System.out.println("上一步运行结果：" + res);
//            return res * 2;
//        });
//        System.out.println("thenApplyAsync:"+future.get());
/**
 *两个都完成
 * */
        CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("future1线程启动： " + Thread.currentThread().getId());
            int i = 10 / 4;
            System.out.println("future1运行结果：" + i);
            return i;
        }, executor);
        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
            System.out.println("future2线程启动");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("future2线程结束");
            return "Hello";
        }, executor);
//        //任务1，2运行结束后开启任务3；不能感知结果、无返回值
        future1.runAfterBothAsync(future2,()->{
            System.out.println("任务三开始");
        },executor);
//        //任务1，2运行结束后开启任务3；能感知结果、无返回值
//        future1.thenAcceptBothAsync(future2,(f1,f2)->{
//            System.out.println("任务3开始，f1->"+f1+"   f2->"+f2);
//        },executor);
//        //任务1，2运行结束后开启任务3；能感知结果、有返回值
//        CompletableFuture<String> future3 = future1.thenCombineAsync(future2, (f1, f2) -> {
//            System.out.println();
//            System.out.println("任务3开始，f1:" + f1 + "   f2:" + f2);
//            return f1 + f2;
//        }, executor);
//        System.out.println("任务3执行结果:"+future3.get());
/**
 *任意一个完成
 * runAfterEitherAsync:不感知结果、无返回值
 *          future1线程启动： 11
 *          future1运行结果：2
 *          future2线程启动
 *          任务3启动
 *          future2线程结束
 * acceptEitherAsync：感知结果、无返回值
 *          future1线程启动： 11
 *          future1运行结果：2
 *          future2线程启动
 *          任务3启动,感知结果：2
 *          future2线程结束
 * applyToEitherAsync: 感知结果、有返回值
 *          future1线程启动： 11
 *          future1运行结果：2
 *          future2线程启动
 *          任务3启动,感知结果：2
 *          任务3结束，返回结果：2
 *          future2线程结束
 * */
//    future1.runAfterEitherAsync(future2,()->{
//        System.out.println("任务3启动");
//    },executor);

//    future1.acceptEitherAsync(future2,res->{
//        System.out.println("任务3启动,感知结果："+res);
//    },executor);

//        CompletableFuture<Object> future3 = future1.applyToEitherAsync(future2, (res) -> {
//            System.out.println("任务3启动,感知结果：" + res);
//            return res;
//        }, executor);
//        System.out.println("任务3结束，返回结果："+future3.get());

/**
 * 多任务组合
 *CompletableFuture.allOf
 *          main...start....
 *          future1线程启动： 11
 *          future1运行结果：2
 *          future2线程启动
 *          future2线程结束
 *          main...end...
 * CompletableFuture.anyOf
 *          main...start....
 *          future1线程启动： 11
 *          future1运行结果：2
 *          main...end...
 *          future2线程启动
 *          future2线程结束
 * */
        CompletableFuture<Void> allOf = CompletableFuture.allOf(future1, future2);
        allOf.get();//等待所有结果完成
//        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future1, future2);
//        anyOf.get();//等待任一结果完成
        System.out.println("main...end...");
}

    /**
     * 测试线程
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public  void testTread(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start....");
        /**
         * 1、继承thread
         *         Thread01 thread01 = new Thread01();
         *         thread01.start();
         *
         * 2、实现Runnable接口
         *         Runnable01 runnable01 = new Runnable01();
         *         new Thread(runnable01).start();
         * 3、实现Callable接口+FutureTask
         *         FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
         *         new Thread(futureTask).start();
         *         Integer res = futureTask.get();// 阻塞 等待整个线程执行完成获取返回结果
         *         System.out.println("futureTask:"+res);
         * 4、线程池
         * executorService.execute(new Runnable01());
         *         4.1 Executors创建
         *         4.2 原生创建方式
         *              corePoolSize:核心线程数（一直存在，除非设置了allowCoreThreadTimeOut）；线程池创建好准备就绪的线程数量
         *              maximumPoolSize：最大线程数量；控制资源并发
         *              keepAliveTime：存活时间； 空闲大于指定时间会被释放（maximumPoolSize - corePoolSize）
         *              unit：时间单位
         *              BlockingQueue<Runnable> workQueue：阻塞队列。多的任务会放到队列中，空闲线程会从队列中获取执行任务
         *              threadFactory：线程创建工厂
         *              handler：如果队列满了，按照指定的拒绝策略拒绝任务
         *        4.3 工作顺序
         *              4.3.1 线程池创建，准备好 core 数量的核心线程，准备接受任务
         *              4.3.2 新的任务进来，用 core 准备好的空闲线程执行。
         *                      4.3.2.1 core满了，就将再进来的任务放入阻塞队列中。空闲的core就会自己去阻塞队 列获取任务执行
         *                      4.3.2.2 阻塞队列满了，就直接开新线程执行，最大只能开到max指定的数量
         *                      4.3.2.3 max都执行好了。Max-core数量空闲的线程会在keepAliveTime指定的时间后自
         *                                  动销毁。最终保持到 core 大小
         *                        4.3.2.4 如果线程数开到了max的数量，还有新任务进来，就会使用reject指定的拒绝策
         *                                  略进行处理
         * LinkedBlockingQueue:  this(Integer.MAX_VALUE);  默认是Integer的最大值；根据压力测试系统峰值指定
             * 拒绝策略：
             * AbortPolicy：丢弃；抛异常
             * CallerRunsPolicy:
             * DiscardOldestPolicy:丢弃最老任务
             *DiscardPolicy:丢弃最新任务；不抛异常
         *
         * */
        //  业务代码中以上三种线程启动方式都不用  每有一个业务会创建一个线程，可能会导致线程资源耗尽
        //  应该将所有的多线程任务都交给线程池执行
//        new Thread(()-> System.out.println("hello")).start();
//      应保证线程池在当前系统中只有一两个，每个异步任务提交给线程池执行

        new ThreadPoolExecutor(5,
                200,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
                );
        System.out.println("main...end....");
//        Executors.newCachedThreadPool();
//        Executors.newFixedThreadPool();
//        Executors.newScheduledThreadPool();
        Executors.newSingleThreadExecutor();

    }


    public static class Thread01 extends Thread{
        public void run(){
            System.out.println("当前线程： "+Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果："+i);
        }
    }

    public static class Runnable01 implements Runnable{
        @Override
        public void run() {
            System.out.println("当前线程： "+Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果："+i);
        }
    }

    public static class Callable01 implements Callable<Integer>{

        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程： "+Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("运行结果："+i);
            return i;
        }
    }
}
